/*
 * filemanager 1.0 - Plugin for jQuery
 * 
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Depends:	
 *   jquery.js
 *	 jquery.xWindow.js
 * 	 jquery.xTree.js
 *
 *  Copyright (c) 2008 Oleg Slobodskoi (ajaxsoft.de)
 */

;(function($) {
	
	$.fn.extend({
		filemanager: function( options ) {

			var	args = Array.prototype.slice.call(arguments, 1);

			return this.each(function() {
				var method = (typeof options == 'string') ? options : 'init',
					filemanager = $.data(this, 'filemanager') || $.data( this, 'filemanager', new $.filemanager(this, options));
				filemanager[method].apply(filemanager, args);
			});

		}
	});

	$.filemanager = function(elem, options)
	{
	
	
	
		/**************************************************************************/
		//Defaults (private)

		var d = {
			view: 'listView', // listView or galleryView
			animate: true,
			speed: 150,
			multiselect: true,
			resizable: true,
			resizableOptions: {
				helper: 'clone', // clone || original
				opacity: 0.7,
				axis: 'x',
				minLeftWidth: 100,
				minRightWidth: 200
			},	
			xWindowOptions: null,
			root: '/media',
			previewPath: '/testimages/',
			currentPath: '/',
			elements: [],
			iconsRoot: '../xIcons/16x16/',
			icons: {
				image: 'image.png',
				pdf: 'page_white_acrobat.png',
				word: 'page_word.png',
				excel: 'page_white_excel.png',
				folder: 'folder.png',
				video: 'film.png',
				buffer: 'page_white_paste.png'
			},
			filter: [
				{
					type: '*',
					name: 'Alle Dateien anzeigen'
				},
				{
					type: 'image',
					name: 'Nur Bilder anzeigen'
				},
				{
					type: 'pdf',
					name: 'Nur PDF Dokumente anzeigen'
				},
				{
					type: 'word',
					name: 'Nur Word Dokumente anzeigen'
				}
				
			],
			allowedSelectionType: '*',
			sort: null,
			
			splitPaneTemplateId: 'splitPaneTemplate',
			galleryViewContainerTemplateId: 'galleryViewContainerTemplate',
			galleryViewItemTemplateId: 'galleryViewItemTemplate',
			listViewContainerTemplateId: 'listViewContainerTemplate',
			listViewItemTemplateId: 'listViewItemTemplate',
			treeItemsTemplateId: 'treeItemsTemplate',
			detailViewTemplateId: 'detailViewTemplate',
			selectionListTemplateId: 'selectionListTemplate',
			newFolderTabTemplateId: 'newFolderTabTemplate',
			newFileTabTemplateId: 'newFileTabTemplate',
			uploadTabTemplateId: 'uploadTabTemplate',
			
			//callbacks
			open: function(){},
			expand: function(){},
			edit: function(){},
			copy: function(){},
			cut: function(){},
			remove: function(){},
			ls: function(){},
			search: function(){},
			saveDetails: function(){},
			uploadClose: function(){},
			uploadOpen: null,
			createFolder: null,
			createFile: null
			
		};

		var wd = {
			title: 'Filemanager',
			width: 995,
			height: 500,
			resize: resizeContents,
			status: '',
			close: function(){
				d.uploadClose(self);
			}
		};

		$.extend(d, options);
		$.extend(wd, options.xWindowOptions);

		var elementDefaults = {
			id: '',
			path: d.currentPath,
			name: '',
			label: '',
			size: '',
			resolution: '',
			ctime: '',
			mtime: '',
			descr: '',
			previewPath: d.previewPath,
			preview: '',
			type: '',
			iconsRoot: d.iconsRoot,
			icons: d.icons,
			view: '',
			keywords: '',
			allowedSelectionType: d.allowedSelectionType,
			root: d.root
		};
		
		
		/**************************************************************************/
		//Privat variables

		var 
			$elem = $(elem),
			$tree, $listView,
			$selectionList,
			$left, $right,
			$listViewContainer,
			$listViewHeader,
			$galleryViewContainer,
			$filter,
			$tabs,
			self = this,
			handleWidth = 0,
			toolbarHeight = 0,
			listViewHeaderHeight = 0,
			selectionListHeight = 0,
			selectionListHeaderHeight = 0,
			tabsHeight = 0,
			elements = d.elements,
			selected = [],
			bufferElement = null,
			bufferAction = null,
			xWindow,
			expanded = [],
			
			//Precompile Templates
			galleryViewItemTemplate = template(d.galleryViewItemTemplateId),
			listViewContainerTemplate = template(d.listViewContainerTemplateId),
			listViewItemTemplate = template(d.listViewItemTemplateId),
			treeItemsTemplate = template(d.treeItemsTemplateId),
			detailViewTemplate = template(d.detailViewTemplateId),
			selectionListTemplate = template(d.selectionListTemplateId),
			newFolderTabTemplate = template(d.newFolderTabTemplateId),
			newFileTabTemplate = template(d.newFileTabTemplateId),
			uploadTabTemplate = template(d.uploadTabTemplateId)
		;
	

		/**************************************************************************/
		//Public variables

		this.$elem = $elem;
		this.filter = '*';
		this.sort = d.sort || [];
		this.view = d.view;
		this.currentElement = {
			id: null,
			name: 'root',
			type: 'folder',
			root: d.root,
			path: d.currentPath
		};
		this.elements = elements;
		this.$selectedTreeItem;
		
		
		
		/**************************************************************************/
		//Public methods
		
		this.init = function ()
		{
			create();
			$elem.xWindow('object', function(obj){
				xWindow = obj;
			});
			tree(elements);
			listView();
			updateListView(elements[0].elements || elements); 			
			$elem.xWindow('object', resizeContents);
			
		};
		
		this.defaults = function ( param )
		{
			typeof param == 'object' ? $.extend(d, param) : createCallback(param, [d]);
		};
		
		this.path = function ( param )
		{
			/^[\s[]?function/.test( param + "" )  && createCallback(param, [self.currentElement.path]);
			if (typeof param == 'string') self.currentElement.path = param;
			if (!param) return self.currentElement.path;
		};
		
		this.collapse = function (id)
		{
			var $item = $('#tree-item-id-'+id).children('.items-container');
			d.animate ? $item.slideUp(d.speed) : $item.show();
			$('#tree-item-id-'+id).children('.item-bg').children('span:first').attr('class','arrow-right');
		};
	
		this.updateTreeItem = function(opt)
		{
			var  $container = $('#tree-item-id-'+opt.parent).children('.items-container');
			if ($container && $container.length)
			{
				var params = $container.attr('rel').split(':'),
					paddingLeft = parseInt(params[0]) +15 || 1,
					color = params[1] == 'grey' ? '' : 'grey'
				;

				$container.get(0).innerHTML = treeItemsTemplate({
					elements: opt.elements, 
					elementDefaults: elementDefaults, 
					color: color, 
					paddingLeft: paddingLeft,
					self: self
				});					
	
				expand([opt.parent]);
			};
		};


		this.select = function( param )
		{	
			typeof param == 'array' ? 			
			$.each(param, function(i, val){
				$right.find('#'+val).find('input:checkbox').click();				
			}) : createCallback(param,[selected]);
		};
		
		this.update = function (elems)
		{
			elements = elems;
			//prepend the buffer item
			bufferElement && elements.unshift(bufferElement);
			self.view == 'listView' ? listView() && updateListView(elements) : galleryView() && updateGalleryView(elements);
			//check selected items
			$.each(selected, function(i, val){
				$('#'+val.id).find('input:checkbox').attr('checked','checked');
			});
			//uncheck select all checkbox
			$('#filemanager-select-all').attr('checked','');
			$elem.xWindow('object', resizeContents);

			self.selectTreeItem();
			
			
		};



		this.detailView = function (data)
		{
			var newData = $.extend({}, elementDefaults, {view: self.view, path: self.currentElement.path}, data);
			$right.attr('class','detail-view').get(0).innerHTML = detailViewTemplate(newData);			
		};

		this.selectTreeItem = function ()
		{
			if (self.currentElement.type != 'folder') return;

			var id = self.currentElement.id,
				$elem = $tree.find('#tree-item-id-'+id);
			if ($elem.length==0) return;
			self.updateTreeItem({parent: id, elements: elements});
			$tree.get(0).scrollTop = $elem.offset().top-$tree.height()/2;
			self.$selectedTreeItem && self.$selectedTreeItem.removeClass('selected');
			self.$selectedTreeItem = $elem.children('.item-bg');
			self.$selectedTreeItem.addClass('selected');
		};
		
		this.resetForms = function ()
		{
			$tabs.find('input, textarea').val('');
		};
		
		/**************************************************************************/
		//Private methods

		function create ()
		{
			var $handle;
			
			$elem.get(0).innerHTML = template(d.splitPaneTemplateId,{
				filter: d.filter,
				draggable: d.draggable,
				uploadOpen: d.uploadOpen,
				createFolder: d.createFolder,
				createFile: d.createFile
			});

			$elem.xWindow(wd).addClass('filemanager').
			click(clickHandler).
			change(function(e){
				e.target.name == 'filter' && createCallback(filterChange, [e.target.value]);
			});

			
			$tree = $('#filemanager-tree');
			$selectionList = $('#filemanager-selection-list');
			$right = $('#filemanager-split-pane-right');
			$handle = $('#filemanager-split-pane-handle');
			$tabs = $('#filemanager-tabs');
			$tabsContent = $('#filemanager-tabs-content');
			
			selectionListHeaderHeight = $('#filemanager-selection-list-header').innerHeight();
			selectionListHeight = $selectionList.innerHeight();
			toolbarHeight = $('#filemanager-toolbar').innerHeight();
			handleWidth = $handle.width();
			tabsHeight = $tabs.innerHeight();
			


			//***********************************************
			
			//add draggables
			if ( d.resizable && $.fn.draggable ) 
			{
				var size;	
				$.extend(d.resizableOptions, {
					start: function(e, ui){
						$elem.xWindow('size', function(s){
							size = s;
						});
					},
					stop: function(e,ui)
					{
						var width;
						if (ui.position.left < d.resizableOptions.minLeftWidth+handleWidth)
							width = d.resizableOptions.minLeftWidth+handleWidth;
						else if (ui.position.left > size.width-d.resizableOptions.minRightWidth-handleWidth)
							width = size.width-d.resizableOptions.minRightWidth-handleWidth;
						else
							width = ui.position.left; 
						
					
						$tree.width(width);
					},
					drag: function(e,ui){
						//ui.position.left<= d.resizableOptions.minLeftWidth && $(document).mouseup();
						//ui.position.left>= size.width-d.resizableOptions.minRightWidth						
					}	 
				});
				$handle.draggable(d.resizableOptions);
			};	
			var searchText = '';
			$('#filemanager-search').typeListener(
				{
					start: function(elem, $abortHandle){
						$abortHandle.show();
					},
					abort: function(elem, $abortHandle){
						$abortHandle.hide();
						$elem.parent().children('.xWindow-buttons-panel').children('.focus').focus();
						elem.value = '';
						self.update(elements);
					},
					abortHandle: '#filemanager-search-abort-handle'
				}, 
				function (text, elem)
				{	
					text != searchText && text.length>1 && search(text, $('#search-target').val());
				}
			);	
			

		};
		
		

		
		
		function clickHandler (e)
		{
			var data = $(e.target).attr('rel');
			if (data)
			{	
				data = data.split(':');
				var f = data[0];
				data.shift();
				data.push(e);
				
				if (typeof data[0] == 'string')
					data[0] = data[0].replace(/tree-item-id-/,'');
				createCallback(f,data);
			};
		};
		
		
		
		function resizeContents ()
		{
				$tree && $tree.height(xWindow.contentSize.height - toolbarHeight- selectionListHeight-23);
				if (self.view == 'listView')
				{
					$listViewContainer && $listViewContainer.height(xWindow.contentSize.height - toolbarHeight - listViewHeaderHeight - tabsHeight);
				} else if (self.view == 'galleryView')
				{
					$galleryViewContainer && $galleryViewContainer.height(xWindow.contentSize.height - toolbarHeight-tabsHeight-21);
				};
		};	

		
		//***********************************************
		//Toolbar private methods
				
		function filterChange (filter)
		{
			var tempElems = [],
				oElements = elements
			;

			self.filter = filter;
			
			filter != '*'
			?
				$.each(elements, function(i,val){
					val.type == filter && tempElems.push(elements[i]);
				})
			:
				tempElems = elements;
			
			self.update(tempElems);
			elements = oElements; 
		};
		


		
		
		//***********************************************
		//Tree private methods


		function tree (elements)
		{
			$tree.get(0).innerHTML = treeItemsTemplate({
				elements: elements, 
				elementDefaults: elementDefaults, 
				color: '', 
				paddingLeft: 1, 
				self: self
			});	
		};
				
		function expand (id)
		{
			var $item, elems = [];
			$.each(id,function(i,id){
				$item = $('#tree-item-id-'+id);
				while ($item.length)
				{
					$item = $item.children('.items-container');
					elems.push($item);
				};
				elems.pop();
	
				for (var i=elems.length-1;i>=0;i--)
				{
					d.animate ? $(elems[i]).slideDown(d.speed) : $(elems[i]).show();
					$(elems[i]).parent().children('.item-bg').children('span:first').attr('class','arrow-down');
				};
			});
		};			
		
		function switchView (view, e)
		{
			//remove buffer element
			elements[0].type == 'buffer' && elements.shift();
			eval(view+'()');
			self.view = view;
			e.target.parentNode.className = 'view '+view;
			createCallback(d.open, [self.currentElement.id, self.currentElement.path, '', self.currentElement.type, self.view]);
		};


		//***********************************************
		//ListView private methods
		
		function listView ()
		{
			$right.attr('class','right').get(0).innerHTML = listViewContainerTemplate({
				sort: self.sort,
				multiselect: d.multiselect
			});	
			$listView = $('#filemanager-list-view');
			$listViewContainer = $('#filemanager-list-view-container');
			$listViewHeader = $('#filemanager-list-view-header');
			listViewHeaderHeight = $listViewHeader.height();
			return true;
		};

		function updateListView (elements)
		{
			var items = '', color = 'grey';

			$.each(elements, function(i,val){
				items+= createListViewItem(val, color);
				color = color ? '' : 'grey';
			});

			$.browser.msie ? $listView.html(items) : $listView.get(0).innerHTML = items;			

		};

		function createListViewItem (obj, color)
		{
			var newObj = $.extend({},elementDefaults,obj,{
				color: color
			});
			return listViewItemTemplate(newObj);				
		};
		

		//***********************************************
		//GalleryView private methods
		function galleryView ()
		{	
			$right.attr('class','gallery-view').
			get(0).innerHTML = template(d.galleryViewContainerTemplateId,{multiselect: d.multiselect});
			
			$galleryViewContainer = $('#filemanager-gallery-view-container');
			return true;
		};	
		
		function updateGalleryView (elements)
		{
			var items = '';

			$.each(elements, function(i,val){
				items+= createGalleryViewItem(val);
			});

			$galleryViewContainer.get(0).innerHTML = items;
		};	
		
		function createGalleryViewItem (obj)
		{
			var newObj = $.extend({},elementDefaults,obj);		
			return galleryViewItemTemplate(newObj);				
		};
		

		
		//***********************************************
		//Helper functions		
		//dummy functions to prevent errors

		function createCallback (fn,params)
		{	
			typeof fn == 'string' && eval('fn='+fn);
			typeof fn == 'function' && fn.apply(self,params);
		};			
		
		
		function select (id, path, name, type, e)
		{	
			$.each(selected, function(i, val){
				!d.multiselect ? $('#'+val.id).find('input').attr('checked','') : val && val.id == id && selected.splice(i,1);	
			});

			if (!d.multiselect) selected = [];
			e.target.checked && selected.push({id: id, path: path, name: name, type: type});

			updateSelectionList();
		};
		
		function unselect (id, e)
		{
			$.each(selected, function(i, val){
				val && val.id == id && selected.splice(i,1) && $('#'+id+' input').attr('checked','');
			});			
			updateSelectionList();
		};
		
		function selectAll (e)
		{	
			selected = [];

			e.target.checked &&
			$.each(elements, function(i, val){
				selected.push({id: val.id, path: val.path, name: val.name, type: val.type});
			});
			
			$right.find('input').each(function(){
				this.checked = e.target.checked;
			});
			
			updateSelectionList();
		};
		
		function updateSelectionList ()
		{
			$selectionList.get(0).innerHTML = selectionListTemplate({selected: selected, iconsRoot: d.iconsRoot, icons: d.icons});
		};
		
		
		function open (id, path, name, type, e)
		{
			if (type == 'buffer')
			{
				createCallback(d[bufferAction], [id, path, self.currentElement.path, name]);
				bufferElement = null;
			} else
			{
				$.extend(self.currentElement, {
					id: id,
					path: path,
					name: name,
					type: type
				});
				
				createCallback(d.open, [id, path, name, type, self.view]);
				$('#tabs-path').text(path);
			};
		};
		
		function toggleTree (id, path, name, e)
		{
			$('#tree-item-id-'+id).children('.items-container').css('display') == 'none' ? 	createCallback(d.expand,[id, path, name]) : self.collapse(id);
		};
		
		function edit (id, path, name, type, e)
		{	
			createCallback(d.edit,[id,path,name,type]);
		};
					
		function copy (id, path, name, type, e)
		{	
		
			bufferElement = {
				id: id,
				path: path,
				name: name,
				type: 'buffer'
			};
			bufferAction = 'copy';	
			$('#'+id).addClass('disabled');
		};

		function cut (id, path, name, type, e)
		{	
			bufferElement = {
				id: id,
				path: path,
				name: name,
				type: 'buffer'
			};
			bufferAction = 'cut';
		};

		function remove (id, path, name, type, e)
		{	
			if (type != 'buffer')
				$('<div/>').xWindow(
					'confirm',
					{
						title: 'Datei entfernen', 
						content: 'Wollen Sie die Datei "'+d.root+path+name+'" wirklich l&ouml;schen?'
					}, 
					function(){
						createCallback(d.remove,[id,path,name,type]);
					}
				);
			else
			{
				bufferElement = null;
				elements.shift();
				$('#'+id).remove();
			};
		};
		
		function saveDetails (id, e)
		{
			var formData = {};
			$right.find('input.text').each(function(){
				formData[this.name] = this.value;
			});
			createCallback(d.saveDetails,[self.currentElement, formData]);
		};
		
		function ls (e)
		{
			createCallback(d.ls, [self.currentElement.path]);
		};
		
		function sort (by, e)
		{	
			var direction = e.target.className;
				$listViewHeader.find('span').attr('class','');		
				e.target.className = (!direction || direction == 'desc') ? 'asc' : 'desc';
			
			
			//do sort
			elements = elements.sort(sortHandler);
			function sortHandler(elem1, elem2)
			{
				var arr = [ elem1[by], elem2[by] ], ret = 0;
				ret = (parseInt(arr[0])!='NaN' && parseInt(arr[1])!='NaN') 
				?
					arr[0]<arr[1] ? 1 : -1 //compare as number
				:
					arr.sort()[0] == arr[0] ? 1 : -1; //compare as string				
				
				return direction == 'asc' ?	ret : ret*-1;
			};

			self.sort = [by, direction];
			updateListView(elements);

		};

		function search (text, target)
		{
			createCallback(d.search, target == 'local' ? [text, self.path()] : [text]);
		};
		
		function contextmenu ()
		{
		
		};

		function createFolder (id)
		{
			createCallback(d.createFolder, [self.currentElement.path, $('#'+id).val()]);
		};
		
		function createFile (id)
		{
			createCallback(d.createFile, [self.currentElement.path, $('#'+id).val()]);
		};		
		
		function switchTab (sw, e)
		{
			$tabs.children('.close').show();
			var active = $(e.target).hasClass('active');
			$tabs.children().removeClass('active');
			//set height of tab to 50% of content
			$tabsContent.css('display')=='none' &&
			$elem.xWindow('object', function(xWindow){
				$tabsContent.height((xWindow.contentSize.height - toolbarHeight - tabsHeight - listViewHeaderHeight-20)/2);
			}); 
			

			//close tab
			active ?
				$tabsContent.empty().slideUp(d.speed, function(){
					$('#filemanager-tabs-close').hide();
					sw == 'upload' && d.uploadClose(self);	
					resizeContainer();
				})
			:
			//open tab
				$tabsContent.slideDown(d.speed, function(){
					sw == 'upload' && $tabsContent.html(uploadTabTemplate(self.currentElement)) && d.uploadOpen(self);
					sw == 'newFolder' && $tabsContent.html( newFolderTabTemplate(self.currentElement) );
					sw == 'newFile' && $tabsContent.html(newFileTabTemplate(self.currentElement));
					resizeContainer();
					$(e.target).addClass('active');
				});
			

			
		};
	
		function resizeContainer ()
		{
			tabsHeight = $tabs.height();
			resizeContents();
		};	

		function closeTabs (e)
		{
			$('#filemanager-tabs-close').hide();
			$tabs.children().removeClass('active');
			$tabsContent.empty().slideUp(d.speed, resizeContainer);	
			d.uploadClose(self);
		};
		
		function preloadImage(src, callback)
		{
			var image= new Image();
			image.onload=callback;
			image.src= src;
		};
				

	};//end of filemanager


	
})(jQuery);
